package http_middleware

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"net/http"
	"strings"
	"time"
)

// TokenExpireDuration token有效期24小时
const TokenExpireDuration = time.Hour * 24

// RefreshTokenExpireDuration refreshToken有效期7天
const RefreshTokenExpireDuration = time.Hour * 24 * 7

// Issuer 签发人
const Issuer = "HNDZ"

var MySecret = []byte("123456")

type MyClaims struct {
	UserId string
	jwt.RegisteredClaims
}

// GenToken 生成JWT
// return tokenString, refreshTokenString, error
func GenToken(userId string) (string, string, error) {
	// 创建一个我们自己的声明
	c := MyClaims{
		UserId: userId, // 自定义字段
		RegisteredClaims: jwt.RegisteredClaims{
			NotBefore: jwt.NewNumericDate(time.Now()),
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpireDuration)), // 过期时间
			Issuer:    Issuer,                                                  // 签发人
		},
	}
	// 使用指定的签名方法创建签名对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	// 使用指定的secret签名并获得完整的编码后的字符串token
	tokenString, err := token.SignedString(MySecret)
	if err != nil {
		return "", "", err
	}
	// 创建RefreshToken的声明
	rc := MyClaims{
		UserId: userId, // 自定义字段
		RegisteredClaims: jwt.RegisteredClaims{
			NotBefore: jwt.NewNumericDate(time.Now()),
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(RefreshTokenExpireDuration)), // 过期时间
			Issuer:    Issuer,                                                         // 签发人
		},
	}
	// 使用指定的签名方法创建签名对象
	refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, rc)
	// 使用指定的secret签名并获得完整的编码后的字符串token
	refreshTokenString, err := refreshToken.SignedString(MySecret)
	if err != nil {
		return "", "", err
	}
	return tokenString, refreshTokenString, nil
}

// ParseToken 解析JWT
func ParseToken(tokenString string) (*MyClaims, error) {
	// 解析token
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) {
		return MySecret, nil
	})
	if err != nil {
		return nil, err
	}
	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { // 校验token
		if claims.ExpiresAt.Time.Before(time.Now()) {
			return nil, errors.New("token has expired")
		}
		return claims, nil
	}
	return nil, errors.New("invalid token")
}

func GenNewTokenFromRefreshToken(refreshTokenString string) (string, string, error) {
	claims, err := ParseToken(refreshTokenString)
	if err != nil {
		return "", "", err
	}
	return GenToken(claims.UserId)
}

// JWTAuthMiddleware 基于JWT的认证中间件
func JWTAuthMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
		// 这里假设Token放在Header的Authorization中，并使用Bearer开头
		// 这里的具体实现方式要依据你的实际业务情况决定
		authHeader := c.GetHeader("Authorization")
		//token := c.GetHeader("token")
		//if token != "" {
		//	authHeader = "Bearer " + token
		//}
		if authHeader == "" {
			c.JSON(http.StatusOK, gin.H{
				"code": 401,
				"msg":  "请求头中auth为空",
			})
			c.Abort()
			return
		}
		// 按空格分割
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			c.JSON(http.StatusOK, gin.H{
				"code": 401,
				"msg":  "请求头中auth格式有误",
			})
			c.Abort()
			return
		}
		// parts[1]是获取到的tokenString，我们使用之前定义好的解析JWT的函数来解析它
		mc, err := ParseToken(parts[1])
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"code": 401,
				"msg":  "无效的Token",
			})
			c.Abort()
			return
		}
		// 将当前请求的username信息保存到请求的上下文c上
		c.Set("userId", mc.UserId)
		c.Next() // 后续的处理函数可以用过c.Get("username")来获取当前请求的用户信息
	}
}

//注册一个/home路由，发个请求验证一下吧。

func HomeHandler(c *gin.Context) {
	userId := c.MustGet("userId").(uint)
	c.JSON(http.StatusOK, gin.H{
		"code": 2000,
		"msg":  "success",
		"data": gin.H{"username": userId},
	})
}
